package com.meichis.mcsappframework.http.download;

import android.os.Handler;
import android.os.Looper;

import com.meichis.mcsappframework.BaseApplication;
import com.meichis.mcsappframework.utils.Tools;

import java.io.*;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

/**
 * Created by jsrgc on 2017/5/31.
 */

public class DownSubscriber<ResponseBody extends okhttp3.ResponseBody> implements Observer<ResponseBody> {

    private String url;
    private String destFileDir;
    private String destFileName;
    private DownLoadCallBack callBack;
    private Handler handler;
    private Disposable d;


    public DownSubscriber(String url, String destFileDir, String destFileName, DownLoadCallBack callBack) {
        this.destFileDir = destFileDir;
        this.destFileName = destFileName;
        this.callBack = callBack;
        handler = new Handler(Looper.getMainLooper());
        this.url = url;
    }

    @Override
    public void onSubscribe(Disposable d) {
        this.d = d;
        if (!Tools.isConnected(BaseApplication.getContext())) {
            finalonError(new Throwable("当前网络不可用，请检查网络情况"));
            onComplete();
        }
    }


    @Override
    public void onComplete() {
        if (!d.isDisposed())
            d.dispose();
        DownManager.getInstance().remove(url);
    }

    @Override
    public void onError(Throwable e) {
        finalonError(e);
        if (!d.isDisposed())
            d.dispose();
        DownManager.getInstance().remove(url);
    }


    @Override
    public void onNext(ResponseBody responseBody) {
        writeResponseBodyToDisk(destFileDir, destFileName, responseBody);
    }

    public Disposable getD() {
        return d;
    }

    /**
     * @param destFileDir
     * @param destFileName
     * @param body
     * @return
     */
    public boolean writeResponseBodyToDisk(String destFileDir, String destFileName, okhttp3.ResponseBody body) {

        InputStream is = null;
        byte[] buf = new byte[2048];
        int len = 0;
        FileOutputStream fos = null;
        try {
            is = body.byteStream();
            final long total = body.contentLength();

            long sum = 0;

            File dir = new File(destFileDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            final File file = new File(dir, destFileName);
            fos = new FileOutputStream(file);
            while ((len = is.read(buf)) != -1) {
                sum += len;
                fos.write(buf, 0, len);
                final long finalSum = sum;
                if (callBack != null) {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callBack.inProgress((int) (finalSum * 100 / total), total);
                        }
                    });
                }
            }
            fos.flush();
            if (callBack != null) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.onResponse(file);
                    }
                });

            }
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            finalonError(new Throwable(e));
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            if (DownManager.getInstance().isDown(url))
                finalonError(new Throwable(e));
            return false;
        } finally {
            try {
                body.close();
                if (is != null) is.close();
            } catch (IOException e) {
            }
            try {
                if (fos != null) fos.close();
            } catch (IOException e) {
            }

        }

    }


    private void finalonError(final Throwable e) {
        if (callBack == null) {
            return;
        }
        handler.post(new Runnable() {
            @Override
            public void run() {
                callBack.onError(e);
            }
        });
    }
}
